package main

//import "fmt"
//import "os"

import (
	"./pack1"
	"fmt"
	"io"
	"log"
	"math"
	"math/rand"
	"os"
	"runtime"
	"strconv"
	"strings"
	"time"
	"unsafe"
)

//const c = "Const"

var GlobalString = "C"
var a string

type ByteSize float64

const (
	_           = iota // 通过赋值给空白标识符来忽略值
	KB ByteSize = 1 << (10 * iota)
	MB
	GB
	TB
	PB
	EB
	ZB
	YB
)

type User struct {
	username string
	age      int32
}

func init() {
	fmt.Println("call main.go before main init")
}

func changeUser(user User) {
	user.username = "changed name"
	fmt.Println("changed->", user.username)
}

func main() {

	//callFuncPrintUser()
	//printImportPackageFuncValue()
	//useFmtPrintfPrintPoint()
	//declarePoint()
	//declareConst()
	//declareVariables()
	//printOsEnv()
	//declareVarInLocalFuncScope()

	//printGlobalString()
	//changeVarInLocalScope()
	//printGlobalString()

	//a = "G"
	//print(a)
	//f1() // print GOG

	//boolVarTest()
	//bitFlagTest()

	//randAndTimePkgTest()

	//timePkgTest()

	//typesAlias()

	//charTest()

	//stringTest()

	//stringFuncTest()

	//DisplayInfo()
	//fmt.Printf("test")

	// test-05.go
	//ifElseTest()
	//switchTest()
	//forTest()
	//forRangeTest()
	//addVal, mulVal := returnValueTest(1,2)
	//fmt.Println("addVal:", addVal, "mulVal:", mulVal)
	//myFunc("hello: ", "test1", "list", "java")

	//min := sliceTestMin(1, 0, 4, 5)
	//slice := []int{18, 1, 23, 4}
	//min2 := sliceTestMin(slice...)
	//fmt.Println("minValue:", min, "min2:", min2)

	//options := Options{par1: 1, par2: 2}
	//var opt2 Options
	//opt2.par2 = 22
	//opt2.par1 = 10
	//structTest(1, 2, opt2)

	//useEmptyInterface(1, "sss", true)
	//fun1RequireDefer()
	//logFunc1("GO")

	//for i := 0; i < 10; i++ {
	//	fibo := fibonacci(i)
	//	fmt.Printf("fibo(%d) = %v\n", i, fibo)
	//}

	//fmt.Println("5 is even:", even(5))
	//fmt.Println("5 is odd:", odd(5))

	//callback1(10, addFunc)
	//callback1(1, func(i int, i2 int) {
	//	v := i * i2
	//	fmt.Println("i*i2", v)
	//})

	//fIndex := strings.IndexFunc("测试", func(r rune) bool {
	//	if r == '试' {
	//		return true
	//	}
	//	return false
	//})
	//fmt.Println("findex:", fIndex)

	//stringReaderTest()

	//fv := func () {
	//	fmt.Println("hello go")
	//}
	//
	//fmt.Printf("fv type -> %T, address -> %v\n", fv, fv)

	//var fAdd = Adder()
	//fmt.Println(fAdd(1), "-")
	//fmt.Println(fAdd(10), "-")
	//fmt.Println(fAdd(20), "-")



	//var addJpeg = makeAddSuffix(".jpge")
	//var addXml = makeAddSuffix(".xml")
	//fmt.Println(addJpeg("img"), addXml("testxml"))

	//pack1.ArraySample01()
	//pack1.SliceSample01()

	pack1.TestInterface3()
}

func where() {
	_, file, line, _ := runtime.Caller(1)
	log.Printf("%s:%d", file, line)
}

func makeAddSuffix(suffix string) func(string) string {
	where()
	return func(s string) string {
		where()
		if !strings.HasSuffix(s, suffix) {
			s += suffix
			where()
		}
		where()
		return s
	}
}

func Adder() func(n int) int {
	var x int
	return func(n int) int {
		x += n
		return x
	}
}

func stringReaderTest() {
	tmpBuf := make([]byte, 10)
	tmpBuf[0] = 'a'
	tmpBuf[1] = 'b'
	tmpBuf[7] = '7'
	tmpBuf[8] = '8'
	tmpBuf[9] = '9'

	tmpStr := string(tmpBuf[8:9])
	fmt.Println("tmpStr:", tmpStr, len(tmpStr))

	str := "this is a long text"
	reader := strings.NewReader(str)
	buf := make([]byte, 4)
	for {
		count, err := reader.Read(buf)
		if err != nil {
			if err == io.EOF {
				fmt.Println("EOF:", count)
				break
			}
		}
		cur := string(buf[:count])
		fmt.Println("cur:", cur, count)
	}
}

func stringFuncTest() {
	str := "test"
	prefixT := strings.HasPrefix(str, "t")
	fmt.Println("test has prefix t:", prefixT)

	suffixT := strings.HasSuffix(str, "t")
	fmt.Println("test has suffix t:", suffixT)

	repeatStr := strings.Repeat("a", 3)
	fmt.Println("repeat str:", repeatStr)

	sl := strings.Fields(str)
	newStr := strings.Join(sl, ";")
	fmt.Println("newStr:", newStr, sl)

	str2 := "win|mac|linux"
	sl2 := strings.Split(str2, "|")
	for _, val := range sl2 {
		fmt.Println("val ->", val)
	}
	newStr2 := strings.Join(sl2, ";")
	fmt.Println("newStr2 -> ", newStr2, sl2)

	oneString := strconv.Itoa(10)
	fmt.Println("str one -> ", oneString)

	oneInt, err := strconv.Atoi("010")
	if err == nil {
		fmt.Println("oneInt->", oneInt)
	} else {
		fmt.Println(err)
	}

	if s, err := strconv.Atoi("4"); err == nil {
		fmt.Printf("%T, %d\n", s, s)
	}

	fmt.Printf("system size: %v", strconv.IntSize)

}

func stringTest() {
	rawString := `This is a raw \n string`
	fmt.Println(rawString)

	//breakString := "one line -> this is escape\nhow line -> string"
	//fmt.Println(breakString)

	str1 := "flash"
	str1Length := len(str1)
	fmt.Println("str1 length:", str1Length)
	//fmt.Println()
	fmt.Printf("first letter: %c\n", str1[0])
	fmt.Printf("last letter: %c\n", str1[str1Length-1])
	first := str1[0]
	if first == 'f' {
		fmt.Println("first letter is equal f")
	}

}

func charTest() {
	var ch byte = 'b'
	if ch == 'b' {
		fmt.Println("is equal b")
	}
}

type TZ int

func typesAlias() {
	var a, b TZ = 1, 2
	c := a + b
	var d int32 = int32(c)
	fmt.Println("d", d)
}

func timePkgTest() {
	now := time.Now()
	fmt.Println("current date: ", now)
	sleepDuration := time.Millisecond * 5000
	time.Sleep(sleepDuration)
	fmt.Println("current date: ", time.Now())

}

func randAndTimePkgTest() {
	intRand := rand.Int()
	fmt.Println("intRand:", intRand)

	for i := 0; i < 10; i++ {
		a := rand.Int()
		fmt.Println("a rand ->", a)
	}

	for i := 0; i < 5; i++ {
		r := rand.Intn(8)
		fmt.Println("r", r)
	}

	fmt.Println()
	//nonaTime := int64(time.Now().Nanosecond())
	//rand.Seed(nonaTime)
	for i := 0; i < 10; i++ {
		//fmt.Printf("%2.2f / ", 100*rand.Float32())
		f := rand.Float32()
		fmt.Printf("%.3f, %f / ", 100*f, f)
	}

	fmt.Println("time", time.Now())
}

func bitFlagTest() {
	type BitFlag int
	const (
		Active BitFlag = 1 << iota
		Send
		Receive
	)

	activeAndSend := Active | Send
	fmt.Println("activeAndSend Value", activeAndSend)
	var value BitFlag = 1
	isSuccess := activeAndSend & value
	fmt.Println("is success", isSuccess)

	strA := "A"
	strB := "B"
	strC := strA + strB
	fmt.Println("strC:", strC)
}

func boolVarTest() {
	age := 10
	agePtr1 := &age
	agePtr2 := &age
	memAddressIsEqual := agePtr1 == agePtr2

	fmt.Println("mem address is equal:", memAddressIsEqual)
	fmt.Println("sizeof agePtr", unsafe.Sizeof(agePtr2))

	username := "test"
	usernamePtr := &username
	fmt.Println("sizeof usernamePtr:", unsafe.Sizeof(usernamePtr))

	var a int = 10
	var b int64 = 20

	var c = int64(a) + b
	fmt.Println("c", c)
	//panic(fmt.Sprint("c > 0"))

	//x := IntFromFloat64(math.MinInt32)
	//fmt.Println("x", x)

}

func IntFromFloat64(x float64) int {
	if math.MinInt32 <= x && x <= math.MaxInt32 { // x lies in the integer range
		whole, fraction := math.Modf(x)
		if fraction >= 0.5 {
			whole++
		}
		return int(whole)
	}
	panic(fmt.Sprintf("%g is out of the int32 range", x))
}

func f1() {
	a := "O"
	print(a)
	f2()
}

func f2() {
	print(a)
}

func printGlobalString() {
	fmt.Println("GLOBAL_STRING", GlobalString)
}

func changeVarInLocalScope() {
	GlobalString = "LOCAL INIT VAR"
	fmt.Println("changeVarInLocalScope ", GlobalString)
}

func declareVarInLocalFuncScope() {
	age := 10
	username := "byref"

	fmt.Println("age", age, "username", username)

	systemOs := runtime.GOOS
	//path := os.Getenv("PATH")

	fmt.Println("os", systemOs)
	//fmt.Printf("system env path", path)

	intVal := 10
	intValPtr := &intVal
	fmt.Println("")
	fmt.Printf("intVal = %d, IntValPtr = %d\n", intVal, *intValPtr)
	*intValPtr = 12
	fmt.Println("change IntValPtr to 12")
	fmt.Printf("intVal = %d, IntValPtr = %d\n", intVal, *intValPtr)

}

func printOsEnv() {
	var goRootEnv = os.Getenv("GOROOT")
	fmt.Println("GOROOT", goRootEnv)

	//fmt.Println(os.Environ())

	var userEnv, ok = os.LookupEnv("USERDOMAIN")
	fmt.Println("OK", ok)
	if ok {
		fmt.Println("UserEnv", userEnv)
	} else {
		fmt.Println("UserEnv Not Exists")
	}

	var javaHomeEnv, javaHomeEnvOk = os.LookupEnv("JAVA_HOME")
	if javaHomeEnvOk {
		fmt.Println("JAVA HOME", javaHomeEnv)
	}
}

func declareVariables() {
	var intVal = 10
	var username = "test"

	var (
		age      = 10
		time     = 10.1
		userType = "json"
	)

	a1, a2, a3 := 1, 2, 3
	fmt.Printf("a1=%d, a2=%d, a3=%d\n", a1, a2, a3)

	var b1, b2 = 1, 2
	fmt.Printf("b1=%d, b2=%d\n", b1, b2)

	const (
		c1, c2 = 2 * iota, iota
		c3, c4 = iota, iota
		_, _
		c5, c6
	)

	fmt.Println("const:", c1, c2, c3, c4, c5, c6)

	fmt.Println(intVal, username, age, time, userType)
	pack1.DisplayUsername()
}

func declareConst() {
	const intVal = 10
	const floatVal = 10.1
	const isOk = false
	const username = "test"

	//var intVal2 int= floatVal
	fmt.Println("floatVal=", floatVal)
	//fmt.Println("intVal2=", intVal2)

	const one, tow, three = 1, 2, "three"
	const (
		Unknown = 0
		Json    = 1
		XML     = 2
	)

	fmt.Println("Enum=", Unknown, Json, XML)

	const ioat = 10
	const (
		a = ioat
		b = ioat
		c = ioat
	)
	fmt.Println("a,b,c", a, b, c)

	const (
		a1 = ioat
		a2
		a3
		a4
		a5 = 1
		a6
	)
	fmt.Println("a1---a6", a1, a2, a3, a4, a5, a5, a6)
}

func declarePoint() {
	var user User
	user.age = 10
	user.username = "my name"

	changeUserByPoint(&user)

	fmt.Println("函数修改指针后结果", user.username)

	s := "good bye"
	var sPoint = &s
	*sPoint = "hello"

	fmt.Printf("memory address: %p\n", sPoint)
	fmt.Printf("sPoint value: %s\n", *sPoint)
	fmt.Printf("s value: %s\n", s)

}

func changeUserByPoint(user *User) {
	user.username = "changedName"
}

// 隐饰声明变量
func implicitDeclareVar() {
	fmt.Println("Καλημέρα κόσμε; or こんにちは 世界")

	rule := "user rule"
	pi := 3.1415926
	fmt.Println("rule->", rule, "pi->", pi)
}

func useFmtPrintfPrintPoint() {
	var user User
	user.age = 10
	user.username = "my name"
	fmt.Printf("user.age=%d, memory address=%p", user.age, &user)
}

func callFuncPrintUser() {
	var user User
	user.username = "test"
	user.age = 10
	changeUser(user)

	printUser(user)
}

func printImportPackageFuncValue() {
	fmt.Println("is authencated", pack1.Is_authenticated())
}

func printUser(user User) {
	user.age = 30
	fmt.Println("printUser#user.age", user.age)
	fmt.Println("printUser#user.username", user.username)
}

// 两个相加
func add(x int, y int) (int, string) {
	return x + y, "x+y="
}
